;-------------------------------------------------------------------------------
; PROPACK Unpack (to VIDEO RAM) Source Code - Game Gear/Master System, Method 1
;
; Copyright (c) 1992-93 Rob Northen Computing, UK. All Rights Reserved.
;
; File: RNC_1VID.S
;
; Date: 07.06.93
;
; Master System conversion by Ian Sabine, Core Design, 7/4/93.
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
; PROPACK Unpack Routine (to VIDEO RAM) - Game Gear/Master System, Method 1
;
; To unpack a PROPACK Method 1 packed file to VIDEO RAM.
;
; Prior to assembling this code you must:
;
; (1) Equate RNC1_BUFBIT. This determines the size of the decompression buffer.
;     The buffer size must be greater than or equal to the size of the buffer
;     specified with the "-d" option when the files were packed with PROPACK.
;
; To call,
;
;               ld   de,VIDEO_ADDRESS       ; pointer in video ram to unpack to
;               ld   hl,PACKED_FILE         ; pointer to packed file
;               call UnpackM1
; On exit,
;
; all general purpose registers are undefined
;-----------------------------------------------------------------------------

;-----------------------------------------------------------------------------
; Video Ram Addresses
;-----------------------------------------------------------------------------

VDP_DAT         EQU $BE                     ; video data port
VDP_COM         EQU $BF                     ; video address port

;-----------------------------------------------------------------------------
; Constants
;-----------------------------------------------------------------------------

RNC1_BUFBIT     EQU 1 ;4                    ; used to define the amount of space
                                            ; needed for the dictionary buffer
                                            ; (this is determined when the files
                                            ;  are packed with the "-d" option)
                                            ; 0 = $100  (256 bytes)
                                            ; 1 = $200  (512 bytes)
                                            ; 2 = $400  ( 1K bytes)
                                            ; 3 = $800  ( 2K bytes)
                                            ; 4 = $1000 ( 4K bytes)
RNC1_BUFSIZE    EQU 1<<(RNC1_BUFBIT+8)      ; actual size of buffer in bytes
RNC1_TABSIZE    EQU 16*8
RNC1_HEADERLEN  EQU 18

;-----------------------------------------------------------------------------
; Variables
;-----------------------------------------------------------------------------

RSSET           $C000                       ; set for maximum bufsize (4K)

; the buffer size determines the start address of the workspace buffer
;
; BUFSIZE       RSSET ADDRESS
; 4K            %1100000000000000 ($C000)
; 2K            %110x000000000000 ($C000, $D000)
; 1K            %110xx00000000000 ($C000, $C800, $D000, $D800)
; 512           %110xxx0000000000 ($C000, $C400, $C800, $CC00, $D000, $D400 etc.)
; 256           %110xxxx000000000 ($C000, $C200, $C400, $C600, $C800, $CA00 etc.)
;

rnc1_dupbuffer  rs.b    RNC1_BUFSIZE
rnc1_rawtab     rs.b    RNC1_TABSIZE
rnc1_postab     rs.b    RNC1_TABSIZE
rnc1_lentab     rs.b    RNC1_TABSIZE
rnc1_counts     rs.w    1
rnc1_bitbuff    rs.l    1
rnc1_blocks     rs.b    1
rnc1_bitcount   rs.b    1
rnc1_huffbitlen rs.b    1
rnc1_huffnum    rs.b    1
rnc1_huffcode   rs.w    1
rnc1_huffbase   rs.w    1
rnc1_stackpos   rs.w    1
rnc1_source     rs.w    1
rnc1_dest       rs.w    1

; total storage space required = BUFSIZE+404

;-----------------------------------------------------------------------------
; Entry Address
; On Entry,
;   de = pointer in video ram to unpack to
;   hl = pointer of packed file
; On Exit,
;   all general purpose registers undefined
;-----------------------------------------------------------------------------
UnpackM1
                ld   a,e
                di
                out  (VDP_COM),a
                ld   a,d
                or   $40
                out  (VDP_COM),a
                ei
                ld   de,rnc1_dupbuffer
                ld   (rnc1_dest),de
                ld   bc,RNC1_HEADERLEN-1
                add  hl,bc
                ld   a,(hl)                 ;input blocks
                inc  hl
                ld   (rnc1_blocks),a
                ld   (rnc1_source),hl
                ld   a,(hl)
                inc  hl
                ld   (rnc1_bitbuff),a
                ld   a,(hl)
                inc  hl
                ld   (rnc1_bitbuff+1),a     ;load 1st word into bit buffer
                xor  a
                ld   (rnc1_bitcount),a      ;init bits in buffer
                ld   a,2
                call .input_bits            ;input lock and key bits
.unpack2
                ld   iy,rnc1_rawtab
                call .make_huftable         ;create raw codes table
                ld   iy,rnc1_postab
                call .make_huftable         ;create offset codes table
                ld   iy,rnc1_lentab
                call .make_huftable         ;create length codes table
                ld   a,16
                call .input_bits            ;input counts
                ld   (rnc1_counts),bc
                jp   .unpack5
.unpack3
                ld   hl,rnc1_postab
                call .input_value           ;input offset
                push bc
                ld   hl,rnc1_lentab
                call .input_value           ;input length
                ld   b,c
                inc  b
                inc  b
                pop  de
                ld   hl,(rnc1_dest)
                scf
                sbc  hl,de
                ld   a,h
                and  $(1<<RNC1_BUFBIT)-1
                or   HB(rnc1_dupbuffer)
                ld   h,a
                ld   de,(rnc1_dest)
.unpack4
                ld   a,(hl)
                inc  hl
                res  RNC1_BUFBIT,h          ; limit size of hl
                out  (VDP_DAT),a
                ld   (de),a
                inc  de
                res  RNC1_BUFBIT,d          ; limit size of de
                djnz .unpack4
                ld   (rnc1_dest),de
.unpack5
                ld   hl,rnc1_rawtab
                call .input_value
                ld   a,b
                or   c
                jr   z,.unpack11            ; branch if count=0
                ld   de,(rnc1_dest)
                ld   hl,(rnc1_source)
                ld   b,c
.unpack6
                ld   a,(hl)
                inc  hl
                out  (VDP_DAT),a
                ld   (de),a
                inc  de
                res  RNC1_BUFBIT,d          ; limit size of de
                djnz .unpack6
                ld   (rnc1_dest),de
                ld   (rnc1_source),hl
                ld   c,(hl)
                inc  hl
                ld   b,(hl)
                inc  hl
                ld   e,(hl)
                inc  hl
                ld   d,(hl)
                ld   hl,(rnc1_bitbuff)
                ld   a,(rnc1_bitcount)
                or   a
                jr   z,.unpack10
                sub  16
                neg
                or   a
                jr   z,.unpack8
.unpack7
                sla  l
                rl   h
                dec  a
                jp   nz,.unpack7
.unpack8
                ld   a,(rnc1_bitcount)
.unpack9
                sla  l
                rl   h
                rl   c
                rl   b
                rl   e
                rl   d
                dec  a
                jp   nz,.unpack9
.unpack10
                ld   (rnc1_bitbuff),bc
                ld   (rnc1_bitbuff+2),de
.unpack11
                ld   a,(rnc1_counts)
                dec  a
                ld   (rnc1_counts),a
                jp   nz,.unpack3
                ld   a,(rnc1_counts+1)
                dec  a
                ld   (rnc1_counts+1),a
                jp   p,.unpack3
                ld   a,(rnc1_blocks)
                dec  a
                ld   (rnc1_blocks),a
                jp   nz,.unpack2
                ret

;------------------------------------------------------------------------------
; input value from packed data
; on entry,
;       hl = huffman table
; on exit,
;       bc = value
; corrupts
;          de
;------------------------------------------------------------------------------
.input_value
                ld   bc,(rnc1_bitbuff)
.input_value2
                ld   a,c                    ;bit_buff
                and  (hl)
                inc  hl
                ld   e,a
                ld   a,b                    ;bit_buff+1
                and  (hl)
                inc  hl
                ld   d,a
                ld   a,(hl)
                inc  hl
                sub  e
                ld   e,a
                ld   a,(hl)
                inc  hl
                sbc  d
                or   e
                jp   nz,.input_value2
                ld   de,16*4-4
                add  hl,de
                ld   a,(hl)
                inc  hl
                ex   af,af
                ld   a,(hl)
                call .input_bits
                ex   af,af
                ld   b,0
                ld   c,a
                cp   2
                jr   c,.input_value4
                dec  a
                push af                     ;save bit shift
                call .input_bits
                ld   e,c                    ;put result in de
                ld   d,b
                pop  bc                     ;restore bit shift
                ld   hl,1
.input_value3
                add  hl,hl
                djnz .input_value3          ;hl=1<<bits
                ld   a,e
                or   l
                ld   c,a
                ld   a,d
                or   h
                ld   b,a                    ;bc=hl|de
.input_value4
                ret

;------------------------------------------------------------------------------
; input data bits from the packed file
; on entry,
;       a = no. of bits to read (1-16)
; on exit,
;       bc = data bits
; corrupts
;       bc',de',hl'
;------------------------------------------------------------------------------
.input_bits
                exx
                ld   c,a                    ;bits to read
                ld   b,c
                ld   hl,1
.input_bits2
                add  hl,hl
                djnz .input_bits2           ;hl=2<<bits
                dec  hl
                ld   a,(rnc1_bitbuff)
                and  l
                ld   l,a
                ld   a,(rnc1_bitbuff+1)
                and  h
                ld   h,a
                push hl                     ;return value
                ld   a,(rnc1_bitcount)      ;(0-16)
                sub  c
                ld   (rnc1_bitcount),a
                jr   nc,.input_bits5
                add  c
                jr   z,.input_bits4
                ld   b,a
                ld   de,(rnc1_bitbuff)
                ld   hl,(rnc1_bitbuff+2)
.input_bits3
                srl  h
                rr   l
                rr   d
                rr   e
                djnz .input_bits3
                ld   (rnc1_bitbuff),de
.input_bits4
                ld   hl,(rnc1_source)
                inc  hl
                inc  hl
                ld   (rnc1_source),hl
                ld   a,(hl)
                inc  hl
                ld   (rnc1_bitbuff+2),a
                ld   a,(hl)
                ld   (rnc1_bitbuff+3),a
                ld   a,(rnc1_bitcount)
                neg
                ld   c,a
                neg
                add  16
                ld   (rnc1_bitcount),a
.input_bits5
                ld   b,c
                ld   de,(rnc1_bitbuff)
                ld   hl,(rnc1_bitbuff+2)
.input_bits6
                srl  h
                rr   l
                rr   d
                rr   e
                djnz .input_bits6
                ld   (rnc1_bitbuff),de
                ld   (rnc1_bitbuff+2),hl
                exx
                pop  bc
                ret

;------------------------------------------------------------------------------
; read huffman code bit lengths and create huffman code table
; on entry,
;       iy -> table
;------------------------------------------------------------------------------
.make_huftable
                ld   (rnc1_stackpos),sp
                ld   hl,(rnc1_stackpos)
                ld   de,-16
                add  hl,de
                ld   sp,hl
                ld   (rnc1_stackpos),hl
                ld   a,5
                call .input_bits            ;read no. of codes
                ld   a,c
                ld   (rnc1_huffnum),a
                or   a
                jp   z,.make_huftable9      ;skip if 0 entries
.make_huftable2
                ex   af,af
                ld   a,4
                call .input_bits
                ld   (hl),c
                inc  hl
                ex   af,af
                dec  a
                jp   nz,.make_huftable2
                ld   ix,(rnc1_stackpos)
                ld   a,1
                ld   (rnc1_huffbitlen),a
                ld   hl,0
                ld   (rnc1_huffcode),hl
                ld   hl,$8000
                ld   (rnc1_huffbase),hl
.make_huftable3
                ld   a,(rnc1_huffnum)
                ld   b,a
                push ix
.make_huftable4
                push bc
                ld   a,(rnc1_huffbitlen)
                cp   (ix+0)
                jr   nz,.make_huftable8
                ld   hl,(rnc1_huffbitlen)   ;+numcodes
                push hl
                ld   hl,(rnc1_huffcode)
                push hl
                ld   a,(rnc1_huffbitlen)
                ld   hl,1
                ld   b,a
.make_huftable5
                add  hl,hl
                djnz .make_huftable5
                dec  hl
                ld   (iy+0),l
                inc  iy
                ld   (iy+0),h
                inc  iy                     ;code mask
                ld   a,(rnc1_huffbitlen)
                sub  a,16
                neg
                ld   b,a
                ld   hl,(rnc1_huffcode)
.make_huftable6
                srl  h
                rr   l
                djnz .make_huftable6
                ld   (rnc1_huffcode),hl
                ld   a,(rnc1_huffbitlen)
                ld   b,a
                ld   hl,(rnc1_huffcode)
                ld   de,0
                or   a
.make_huftable7
                rr   h
                rr   l
                rl   e
                rl   d
                djnz .make_huftable7
                ld   (iy+0),e
                inc  iy
                ld   (iy+0),d
                inc  iy
                push ix
                pop  hl
                ld   de,(rnc1_stackpos)
                or   a
                sbc  hl,de
                ld   h,(ix+0)
                ld   (iy+16*4-4),l
                ld   (iy+16*4-4+1),h
                pop  hl
                ld   de,(rnc1_huffbase)
                add  hl,de
                ld   (rnc1_huffcode),hl
                pop  hl
                ld   (rnc1_huffbitlen),hl   ;+numcodes
.make_huftable8
                inc  ix
                pop  bc
                djnz .make_huftable4
                pop  ix
                ld   hl,(rnc1_huffbase)
                srl  h
                rr   l
                ld   (rnc1_huffbase),hl
                ld   a,(rnc1_huffbitlen)
                inc  a
                ld   (rnc1_huffbitlen),a
                cp   17
                jp   nz,.make_huftable3
.make_huftable9
                ld   hl,(rnc1_stackpos)
                ld   de,16
                add  hl,de
                ld   sp,hl
                ret
